home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C++ / Applications / Nuntius 1.2 / src / Nuntius / UNetAsciiProtocol.cp < prev    next >
Encoding:
Text File  |  1994-02-20  |  10.5 KB  |  485 lines  |  [TEXT/MPS ]

  1. // Copyright © 1992 Peter Speck, speck@dat.ruc.dk. All rights reserved.
  2. // UNetAsciiProtocol.cp
  3.  
  4. #include "UNetAsciiProtocol.h"
  5. #include "UMacTcp.h"
  6. #include "NetAsciiTools.h"
  7. #include "Tools.h"
  8. #include "UThread.h"
  9. #include "UProgress.h"
  10. #include "UPrefsDatabase.h"
  11.  
  12. #ifndef __STDIO__
  13. #include <stdio.h>
  14. #endif
  15.  
  16. #pragma segment MyComm
  17.  
  18. #define qLogCommands qDebug & 0
  19. #define qDebugDumpReceive qDebug & 0
  20. #define qDebugTransmit qDebug & 0
  21. #define qDebugConstruct qDebug & 0
  22.  
  23. FILE *myNAPstderr = nil;
  24. #if FALSE
  25. #if qDebug
  26. #define myNAPstderr myNAPstderr
  27. void OpenNAPOut()
  28. {
  29.     char filename[] = "HD2:Desktop Folder:NAP_log";
  30.     myNAPstderr = fopen(filename, "w");
  31.     if (myNAPstderr == nil)
  32.         DebugStr("Could not open NAP logfile");
  33.     fsetfileinfo(filename, 'MPS ', 'TEXT'); 
  34. }
  35. #endif
  36. #else
  37. #endif
  38.  
  39. const long kInBufferSize = 4 * 1024; // only when using copy-receive from MacTCP
  40.  
  41. const long kOutBufferSize = 4 * 1024;
  42.  
  43. const char CRLF[] = {13, 10};
  44.  
  45. PNetAsciiProtocol::PNetAsciiProtocol()
  46. {
  47. #if qDebugConstruct
  48.     fprintf(stderr, "PNetAsciiProtocol::PNetAsciiProtocol() at $%lx called\n", long(this));
  49. #endif
  50. #ifdef myNAPstderr
  51.     if (myNAPstderr == nil)
  52.         OpenNAPOut();
  53. #else
  54.     myNAPstderr = stderr;
  55. #endif
  56.     fMacTcp = nil;
  57.     fCurrentReceiveP = nil;
  58.     fCurrentReceiveLeft = 0;
  59.     fProgressDelta = 0;
  60.     fReceiveBufferP = nil;
  61.     fTransmitBufferP = nil;
  62.     fCurrentTransmitP = nil;
  63.     fCurrentTransmitChars = 0;
  64.     fRespondLineP = nil;
  65. }
  66.  
  67. void PNetAsciiProtocol::INetAsciiProtocol(long newsServerAddr, short port)
  68. {
  69. #if qDebugConstruct
  70.     fprintf(stderr, "void PNetAsciiProtocol::INetAsciiProtocol() at $%lx called\n", long(this));
  71. #endif
  72.     FailInfo fi;
  73.     if (fi.Try())
  74.     {
  75.         PTcpStream *mt = new PTcpStream();
  76.         mt->ITcpStream(gPrefs->GetLongPrefs('STio'));
  77.         fMacTcp = mt;
  78.         fMacTcp->OpenConnection(newsServerAddr, port);
  79.  
  80.         fRespondLineP = NewPermPtr(kReturnLineBufferSize);
  81.         *fRespondLineP = 0;
  82.         fReceiveBufferP = NewPermPtr(kInBufferSize);
  83.         fCurrentReceiveP = fReceiveBufferP;
  84.         fTransmitBufferP = NewPermPtr(kOutBufferSize);
  85.         fCurrentTransmitP = fTransmitBufferP;
  86.  
  87.         fi.Success();
  88.     }
  89.     else // fail
  90.     {
  91.         delete this;
  92.         fi.ReSignal();
  93.     }
  94. }
  95.  
  96. PNetAsciiProtocol::~PNetAsciiProtocol()
  97. {
  98. #if qDebugConstruct
  99.     fprintf(stderr, "PNetAsciiProtocol::~PNetAsciiProtocol() at $%lx called\n", long(this));
  100. #endif
  101.     fReceiveBufferP = DisposeIfPtr(fReceiveBufferP);
  102.     fTransmitBufferP = DisposeIfPtr(fTransmitBufferP);
  103.     fRespondLineP = DisposeIfPtr(fRespondLineP);
  104.     FreeIfPtrObject(fMacTcp); fMacTcp = nil;
  105. }    
  106.  
  107. // ---------------- PTcpStream stuff
  108. void PNetAsciiProtocol::FillReceiveBuffer()
  109. {
  110.     long noBytes = 0;
  111.     while (!noBytes)
  112.     {
  113.         fMacTcp->ReceiveSomeData(fReceiveBufferP, kInBufferSize, noBytes);
  114.         fCurrentReceiveP = fReceiveBufferP;
  115.         fCurrentReceiveLeft = noBytes;
  116.     }
  117. #if qDebugDumpReceive
  118.     char ss[200];
  119.     Ptr p = fCurrentReceiveP;
  120.     fprintf(myNAPstderr, "Got %ld bytes at %lx\n", noBytes, long(p));
  121.     long l = noBytes;
  122.     long part = 0;
  123.     while (l)
  124.     {
  125.         switch (*p) {
  126.             case 13:
  127.                 ss[part] = '\\';
  128.                 break;
  129.             case 10:
  130.                 ss[part] = '@';
  131.                 break;
  132.             default:
  133.                 ss[part] = *p;
  134.         }
  135.         p++;
  136.         l--;
  137.         part++;
  138.         if (part > 70)
  139.         {
  140.             ss[part] = 0;
  141.             fprintf(myNAPstderr, "Data received: %s\n", ss);
  142.             part = 0;
  143.         }
  144.     }
  145.     ss[part] = 0;
  146.     fprintf(myNAPstderr, "Data received: %s\n", ss);
  147. #endif
  148. }
  149.  
  150. // ---------------- parsing line / dot-end
  151. void PNetAsciiProtocol::CopyChars(Handle h, long noChars, long &curSize)
  152. {
  153. #if qDebugDumpReceive
  154.     fprintf(stderr, "CopyChars, noChars = %ld, curSize %ld -> %ld, ", noChars, curSize, curSize + noChars);
  155.     fprintf(stderr, "fCurrentReceiveLeft %ld -> %ld\n", fCurrentReceiveLeft, fCurrentReceiveLeft - noChars);
  156. #endif
  157. #if qDebug
  158.     if (noChars < 0)
  159.     {
  160.         ProgramBreak("noChars < 0");
  161.         noChars = 0;
  162.     }
  163.     if (noChars > fCurrentReceiveLeft)
  164.     {
  165.         ProgramBreak("noChars > fCurrentReceiveLeft");
  166.         noChars = fCurrentReceiveLeft;
  167.     }
  168. #endif
  169.     SetPermHandleSize(h, curSize + noChars);
  170.     BytesMove(fCurrentReceiveP, *h + curSize, noChars);
  171.     curSize += noChars;
  172.     fCurrentReceiveP += noChars;
  173.     fCurrentReceiveLeft -= noChars;
  174.     UpdateProgress();
  175. }
  176.  
  177. void PNetAsciiProtocol::UpdateDotBuffer(Handle h, Ptr &destP)
  178. {
  179.     UpdateProgress();
  180.     long currSize = destP - *h;
  181.     FillReceiveBuffer(); /* updates fCurrentReceiveP and fCurrentReceiveLeft */
  182.     SetPermHandleSize(h, currSize + fCurrentReceiveLeft);
  183.     destP = *h + currSize;
  184. }
  185.  
  186. Handle PNetAsciiProtocol::GetDotTerminatedText()
  187. {
  188.     Handle h = nil;
  189.     VOLATILE(h);
  190.     FailInfo fi;
  191.     if (fi.Try())
  192.     {
  193.         h = NewPermHandle(0);
  194.         UpdateProgress();
  195.         long size = DoGetDotTerminatedText(h);
  196.         fProgressDelta = Max(0, fProgressDelta - 1); // subtract '.' line
  197. #if qDebug
  198.         if (size < 0)
  199.             ProgramBreak("size < 0, should never could happend!");
  200.         if (size > 120 * 1024)
  201.             fprintf(stderr, "Got a real large GetDotTerminatedText(): %ld bytes\n", size);
  202. #endif
  203.         SetPermHandleSize(h, size + 1);
  204.         *(*h + size) = 0;
  205. #if qDebug
  206.         long zzsize = GetHandleSize(h);
  207.         if (zzsize && *(*h + zzsize - 1) != 0)
  208.             ProgramBreak("The last char is not null (som jeg lovede!)");
  209. #endif
  210.         UpdateProgress();
  211.         fi.Success();
  212.         return h;
  213.     }
  214.     else // fail
  215.     {
  216.         h = DisposeIfHandle(h);
  217.         fi.ReSignal();
  218.     }
  219. }
  220.  
  221. long PNetAsciiProtocol::DoGetDotTerminatedText(Handle h)
  222. // Returns number of received chars. Handle can be larger
  223. {
  224.     SetPermHandleSize(h, fCurrentReceiveLeft);
  225.     Ptr tmpDestP;
  226.     register Ptr destP = *h;
  227.     register Ptr fromP = fCurrentReceiveP;
  228.     register long left = fCurrentReceiveLeft;
  229.     goto TestDot;
  230.     while (true)
  231.     {
  232.  
  233. #define macroCopyNext()        \
  234.         *destP++ = *fromP;        \
  235.         ++fromP;                            \
  236.         --left;
  237. // end macro
  238.  
  239. #define macroCheckLeft()                            \
  240.         if (!left)                                                \
  241.         {                                                                    \
  242.             tmpDestP = destP;                                \
  243.             fCurrentReceiveLeft = left;            \
  244.             fCurrentReceiveP = fromP;                \
  245.             UpdateDotBuffer(h, tmpDestP);        \
  246.             destP = tmpDestP;                                \
  247.             left = fCurrentReceiveLeft;            \
  248.             fromP = fCurrentReceiveP;                \
  249.         }
  250. // end macro
  251.  
  252.         macroCopyNext();
  253.         macroCheckLeft();
  254.         if (*fromP != 13)
  255.             continue;
  256.     
  257.         while (*fromP == 13)
  258.         {
  259.             ++fProgressDelta;
  260.             macroCopyNext();
  261.             macroCheckLeft();
  262.             if (*fromP != 10)
  263.                 break;
  264.             macroCopyNext();
  265.             macroCheckLeft();
  266.         }
  267. TestDot:
  268.         macroCheckLeft();
  269.         if (*fromP != '.')
  270.             continue;
  271.         ++fromP; --left; // skip dot, don't copy it
  272.         macroCheckLeft();
  273.         if (*fromP != 13)
  274.             continue;
  275.         ++fromP; --left; // skip CR, don't copy it
  276.         macroCheckLeft();
  277.         ++fromP; --left; // skip LF, don't copy it
  278.         break; // funny down here!
  279.     }
  280.     fCurrentReceiveLeft = left;
  281.     fCurrentReceiveP = fromP;
  282.     return destP - *h;
  283. }
  284.  
  285. char PNetAsciiProtocol::GetChar()
  286. {
  287.     if (fCurrentReceiveLeft == 0)
  288.         FillReceiveBuffer();
  289.     --fCurrentReceiveLeft;
  290.     return *fCurrentReceiveP++;
  291. }
  292.  
  293. void PNetAsciiProtocol::GetLine()
  294. {
  295.     Ptr destP = fRespondLineP;
  296.     long roomLeft = kReturnLineBufferSize - 5;
  297.  
  298.     char ch = GetChar();
  299.     while (ch != 13 && --roomLeft)
  300.     {
  301.         *destP++ = ch;
  302.         ch = GetChar();
  303.     }
  304.     *destP = 0;
  305.     while (ch != 13)
  306.         ch = GetChar();
  307.     GetChar(); // skip LF
  308. }
  309.  
  310. // ---------------- handling commands
  311. void PNetAsciiProtocol::SendCommand(char *cmd)
  312. {
  313.     SendChars(cmd, strlen(cmd));
  314.     SendChars(CRLF, 2);
  315.     FlushTransmitBuffer();
  316. }
  317.  
  318. void PNetAsciiProtocol::GetRespondLine()
  319. {
  320.     while (true)
  321.     {
  322.         GetLine();
  323.         Ptr p = fRespondLineP;
  324.         short num = 0;
  325.         char ch = *p;
  326.         while (ch && ch >= '0' && ch <= '9')
  327.         {
  328.             num *= 10;
  329.             num += ch - '0';
  330.             ch = *++p;
  331.         }
  332.         LogCommands(fRespondLineP);
  333.         LogCommands("\n");
  334.         if (*p == '-') // multi line, if anybody is using that
  335.             continue;
  336.         fRespondCode = num;
  337.         break;
  338.     }
  339. }
  340.  
  341. // ---------------- transmitting
  342. void PNetAsciiProtocol::FlushTransmitBuffer()
  343. {
  344.     if (!fCurrentTransmitChars)
  345.         return;
  346. #if qDebugTransmit
  347.     char ss[200];
  348.     Ptr p = fTransmitBufferP;
  349.     fprintf(myNAPstderr, "Sending %ld bytes at %lx\n", fCurrentTransmitChars, long(p));
  350.     long l = fCurrentTransmitChars;
  351.     long part = 0;
  352.     while (l)
  353.     {
  354.         if (*p == 13)
  355.                 ss[part] = '\\';
  356.         else if (*p == 10)
  357.             ss[part] = '@';
  358.         else if (*p < 32)
  359.         {
  360.             ss[part++] = '≤';
  361.             ss[part++] = '^';
  362.             ss[part++] = *p + 64;
  363.             ss[part++] = '≥';
  364.         }
  365.         else
  366.             ss[part] = *p;
  367.         p++;
  368.         l--;
  369.         part++;
  370.         if (part > 70)
  371.         {
  372.             ss[part] = 0;
  373.             fprintf(myNAPstderr, "Data sent: %s\n", ss);
  374.             part = 0;
  375.         }
  376.     }
  377.     if (part)
  378.     {
  379.         ss[part] = 0;
  380.         fprintf(myNAPstderr, "Data sent: %s\n", ss);
  381.     }
  382. #endif
  383.     fMacTcp->SendData(fTransmitBufferP, fCurrentTransmitChars);
  384.     fCurrentTransmitP = fTransmitBufferP;
  385.     fCurrentTransmitChars = 0;
  386. }
  387.  
  388. void PNetAsciiProtocol::SendChars(const void *p, long noChars)
  389. {
  390.     register const unsigned char *fromP = (const unsigned char *)(p);
  391.     while (noChars)
  392.     {
  393.         long roomLeft = kOutBufferSize - fCurrentTransmitChars;
  394.         if (!roomLeft) // filled up
  395.         {
  396.             FlushTransmitBuffer();
  397.             roomLeft = kOutBufferSize;
  398.         }
  399.         register long tmpNoChars = Min(noChars, roomLeft);
  400.         BytesMove(fromP, fCurrentTransmitP, tmpNoChars);
  401.         fromP += tmpNoChars;
  402.         fCurrentTransmitP += tmpNoChars;
  403.         fCurrentTransmitChars += tmpNoChars;
  404.         noChars -= tmpNoChars;
  405.     }
  406.     UpdateProgress();
  407. }
  408.  
  409. void PNetAsciiProtocol::SendDotTerminatedText(Handle h)
  410. {
  411.     MakeLastCharCR(h);
  412.     HLock(h);
  413.     register unsigned char *p = (unsigned char *) *h;
  414.     unsigned char *endP = p + GetHandleSize(h) - 1;
  415.     long line = 0;
  416.     Boolean inHeader = true;
  417.     Boolean avoidFormatting = gPrefs->GetBooleanPrefs('2022');
  418.     long wrapLen = gPrefs->GetLongPrefs('WrLn');
  419.     while (p <= endP)
  420.     {
  421.         unsigned char *lineStartP = p;
  422.         while (*p != 13)
  423.             ++p;
  424.         long lineChars = p - lineStartP + 1; // with CR
  425.         while (!avoidFormatting && !inHeader && lineChars > wrapLen) //  We don't want to break headers
  426.         {
  427.             long subLineChars = wrapLen - 1; //with space->cr char
  428.             p = lineStartP + subLineChars - 1;
  429.             while (subLineChars && *p > 32) // a b c _ d e f
  430.             {
  431.                 --p; 
  432.                 --subLineChars;
  433.             }
  434.             if (!subLineChars)
  435.             {
  436.                 subLineChars = wrapLen - 3;
  437.                 p = lineStartP + subLineChars - 1;
  438.             }
  439.             fProgressDelta += subLineChars;
  440.             if (*lineStartP == '.')
  441.                 SendChars(".", 1); // double dot on start of line
  442.             SendChars(lineStartP, subLineChars - 1); // sends CR myself
  443.             SendChars(CRLF, 2);
  444.             if (inHeader)
  445.                 SendChars("     ", 5); // fold header
  446.             lineStartP += subLineChars;
  447.             lineChars -= subLineChars;
  448.         }
  449.         if (inHeader && lineChars <= 1)
  450.             inHeader = false;
  451.         if (*lineStartP == '.')
  452.             SendChars(".", 1); // double dot on start of line
  453.         if (lineChars > 1)
  454.             SendChars(lineStartP, lineChars - 1); // sends CR myself
  455.         SendChars(CRLF, 2);
  456.         fProgressDelta += lineChars;
  457.         p = lineStartP + lineChars;
  458.         if (p <= endP && *p == 10)
  459.             p++;
  460.     }
  461.     SendChars(".", 1);
  462.     SendChars(CRLF, 2);
  463.     HUnlock(h);
  464.     FlushTransmitBuffer();
  465.     UpdateProgress();
  466. }
  467.  
  468. // ---------------- progress
  469. void PNetAsciiProtocol::UpdateProgress()
  470. {
  471.     if (!fProgressDelta)
  472.         return;
  473.     gCurProgress->Worked(fProgressDelta);
  474.     fProgressDelta = 0;
  475. }
  476.  
  477. void PNetAsciiProtocol::LogCommands(char *p)
  478. {
  479. #if qLogCommands
  480.     fprintf(stderr, "%s", p);
  481. #else
  482.     p = p;
  483. #endif
  484. }
  485.